package com.kuang.lock;

import java.util.concurrent.Callable;

/**
 * 1.公平锁、非公平锁：
 *     公平锁：非常公平，不能插队，必须先来后到！
 *     非公平锁：非常不公平，可以插队（默认都是非公平锁）  public ReentrantLock(){sync = new NonfairSync();}
 * 2.可重入锁
 *      拿到了外面的锁之后，就可以拿到里面的锁
 *      测试传统版Synchronized锁
 *      测试结果：A拿到外面的锁，执行sms后，不会释放锁，再拿到call里面的锁，知道执行完后一起释放锁，B再拿到锁
 *      测试可重复锁（lock版锁）：lock锁必须配对
 * 3.自旋锁
 *      不断尝试获取锁，直到成功为止
 *      实现自旋锁：实现方式CAS
 *      测试自旋锁：线程1、线程2，
 *      线程1加锁后，线程2想加锁，得等T1解锁后，T2才能加锁，T2等T1解锁的时候，T2在自旋等待T1释放锁
 * 4.死锁
 *      死锁测试：两个线程互相争抢资源
 *      死锁时，程序卡住，怎么排查哪里死锁？java bin 目录下，
 *          1）使用 jps -l定位进程号   查看当前或者的java进程
 *          2）使用 jstack 进程号，查看死锁信息，找到死锁
 */

// 测试可重入锁（传统版Synchronized版）
// sms一层锁，call一层锁，sms调用call,这时候，两个线程A、B同时sms,
// 假设两个锁不一样，A线程先获取sms的锁，再获取里面call的锁，B线程想获取sms的锁，需要等A释放sms的锁，那A什么时候释放？
// 是在获取call的锁之前，还是释放call锁之后？
// 如果A在获取call之前释放sms的锁，B就可以获取，这时候打印顺序应该是 A：sms, B:sms, A:call, B:call
// 如果A在释放call锁之后释放sms的锁，B就可以获取，这时候打印顺序应该是 A：sms, A:call,B:sms, B:call （√）
// 结论：sms锁包裹call锁，拿到sms锁，就拿到call锁（可重入锁）
public class Test1 {
    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(phone::sms,"A").start();
        new Thread(phone::sms,"B").start();
        /*
            Asms
            Acall
            Bsms
            Bcall
         */
    }
}

class Phone{
    public synchronized void sms(){  // 大锁包小锁，大肠包小肠， 获取大锁，就自动获取小锁，其他线程需要等当前线程释放大锁、小锁后才能获取锁执行
        System.out.println(Thread.currentThread().getName()+"sms");
        call();
    }
    public synchronized void call(){
        System.out.println(Thread.currentThread().getName()+"call");
    }

}
